﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using WebViewerTest.NativeMethods;

namespace WebViewerTest
{
	public class WebRenderer : INotifyPropertyChanged, IDisposable
	{
		public WriteableBitmap BitmapSource { get; private set; }
		public double Progress { get; private set; }
		public Rect ProgressRect { get { return new Rect( 0, 0, Progress, 1 ); } }

		private HiddenWebBrowser browser;
		private Bitmap image;

		public WebRenderer()
		{
			browser = new HiddenWebBrowser();

			browser.Navigated += delegate
			{
				if ( browser.Document != null ) browser.Document.Window.Error += delegate { };
			};

			browser.ProgressChanged += delegate( object sender, WebBrowserProgressChangedEventArgs e )
			{
				Capture( browser, image, BitmapSource );
				SetProgress( (double)e.CurrentProgress / (double)e.MaximumProgress );
			};

			browser.DocumentCompleted += delegate
			{
				Capture( browser, image, BitmapSource );
				SetProgress( 0 );
			};
		}

		public void Capture()
		{
			Capture( browser, image, BitmapSource );
		}

		private void SetProgress( double progress )
		{
			Progress = Math.Max( 0, Math.Min( 1, progress ) );
			OnPropertyChanged( "Progress" );
			OnPropertyChanged( "ProgressRect" );
		}

		public System.Windows.Size Size
		{
			get
			{
				return ( BitmapSource != null )
					? new System.Windows.Size( BitmapSource.Width, BitmapSource.Height )
					: new System.Windows.Size();
			}

			set
			{
				BitmapSource = new WriteableBitmap( (int)value.Width, (int)value.Height, 96, 96, PixelFormats.Pbgra32, null );
				browser.Width = BitmapSource.PixelWidth;
				browser.Height = BitmapSource.PixelHeight;
				image = new Bitmap( BitmapSource.PixelWidth, BitmapSource.PixelHeight );
				Capture( browser, image, BitmapSource );
			}
		}

		private static void Capture( System.Windows.Forms.WebBrowser browser, Bitmap image, WriteableBitmap target )
		{
			var view = browser.ActiveXInstance as IViewObject;

			if ( view != null && image != null )
			{
				var bounds = new COMRECT( 0, 0, image.Width, image.Height );

				using ( var graphics = Graphics.FromImage( image ) )
				{
					var hdc = graphics.GetHdc();
					view.Draw( 1, -1, (IntPtr)0, null, (IntPtr)0, (IntPtr)hdc, bounds, bounds, (IntPtr)0, 0 );
					graphics.ReleaseHdc( hdc );
				}

				var data = image.LockBits(
					new System.Drawing.Rectangle( 0, 0, image.Width, image.Height ),
					System.Drawing.Imaging.ImageLockMode.ReadOnly,
					image.PixelFormat );

				target.WritePixels(
					new Int32Rect( 0, 0, target.PixelWidth, target.PixelHeight ),
					data.Scan0,
					data.Height * data.Stride,
					data.Stride );

				image.UnlockBits( data );
			}
		}

		public void Navigate( Uri uri )
		{
			try
			{
				if ( browser.IsBusy ) browser.Stop();
				browser.Url = uri;
				Progress = 0;
				OnPropertyChanged( "Progress" );
				OnPropertyChanged( "ProgressRect" );
			}
			catch
			{
				//TODO: Error handling :o)
			}
		}

		public Uri Url { get { return browser.Url; } set { Navigate( value ); } }

		public HiddenWebBrowser Browser { get { return browser; } }

		#region INotifyPropertyChanged Members

		public event PropertyChangedEventHandler PropertyChanged;

		private void OnPropertyChanged( string propertyName )
		{
			if ( PropertyChanged != null ) PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			if ( image != null )
			{
				image.Dispose();
				image = null;
			}

			if ( browser != null )
			{
				browser.Dispose();
				browser = null;
			}
		}

		#endregion
	}
}